import { createMD5 } from 'hash-wasm';

const maxChunkSize = 10 * 1024 * 1024; // 每次处理数据块的最大值，1MB
const chunksPerCycle = 100; // 每个计算周期中处理的数据块数

/**
 * 分割文件
 */
export const sliceFile = async (file: File, baseSize = 2) => {
  const chunkSize = baseSize * 1024 * 1024; // KB
  const chunks: {
    blob: Blob;
    md5: string;
    status: 'init' | 'uploading' | 'uploaded' | 'error';
    abortController: AbortController;
  }[] = [];
  let startPos = 0;

  while (startPos < file.size) {
    const chunk = file.slice(startPos, startPos + chunkSize);
    const arrayBuffer = await chunk.arrayBuffer();
    const maker = await createMD5();
    maker.init();
    maker.update(new Uint8Array(arrayBuffer));
    const md5 = maker.digest();

    chunks.push({
      blob: chunk,
      md5,
      status: 'init',
      abortController: new AbortController()
    });
    startPos += chunkSize;
  }

  return chunks;
};

let computeFileMD5Index = 1;

export const computeFileMD5 = (file: File): Promise<string> => {
  const worker = new Worker(new URL('./worker/md5-encode.worker.ts', import.meta.url), {
    type: 'module'
  });

  const taskId = computeFileMD5Index++;
  // const taskId = computeFileMD5Index++
  console.log('开始计算md5', taskId);
  const stamp = Date.now();
  console.time('md计算耗时' + stamp);

  return new Promise((resolve, reject) => {
    // 分片放worker处理
    const fileReader = new FileReader();

    try {
      let currentChunk = 0;
      const totalChunks = Math.ceil(file.size / maxChunkSize);

      // 处理数据块
      const processChunk = (start: number) => {
        try {
          const blobSlice = File.prototype.slice;
          const end = Math.min(start + maxChunkSize, file.size);
          const chunk = blobSlice.call(file, start, end);
          fileReader.readAsArrayBuffer(chunk);
        } catch (e) {
          console.error(e);
        }
      };

      // 文件读取成功
      fileReader.onload = () => {
        /*spark.append(fileReader.result) // 将当前数据块内容追加到 MD5 计算器*/
        worker.postMessage({ taskId, dataBuffer: fileReader.result, status: 'ing' }, [
          fileReader.result
        ] as Transferable[]);

        currentChunk += 1;
        if (currentChunk >= totalChunks) {
          worker.postMessage({ taskId, status: 'end' });
        } else if (currentChunk % chunksPerCycle === 0) {
          // 在处理指定数量的数据块后，设置一个任务延迟以使 UI 线程有空间处理
          setTimeout(() => {
            processChunk(currentChunk * maxChunkSize);
          }, 0);
        } else {
          // 继续处理下一个数据块
          processChunk(currentChunk * maxChunkSize);
        }
      };

      fileReader.onerror = (e) => {
        console.error(e);
        return reject(e);
      };
      worker.onerror = (e) => {
        console.log(e);
        fileReader.abort();
        reject(e);
      };
      worker.onmessage = ({ data }) => {
        const { md5, status, error } = data;
        if (data.taskId !== taskId) {
          return;
        }

        if (status === 'createSuccess') {
          // 开始处理第一个数据块
          processChunk(0);
          return;
        }

        if (status === 'success') {
          resolve(md5);
        } else {
          reject(error);
        }
        fileReader.abort();
        console.timeEnd('md计算耗时' + stamp);
        // worker.terminate()
      };

      worker.postMessage({ taskId, status: 'create' });
    } catch (e) {
      console.error(e);
      fileReader.abort();
      reject(e);
    } finally {
      //
    }
  });
};
